//
// Created by casdon on 2024/8/19.
//

#ifndef CIOT_CSDK_CIOT_CLOUD_H
#define CIOT_CSDK_CIOT_CLOUD_H

#include "types.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef enum Ciot_cloud_topic_e
{
    Ciot_cloud_topic_timeSync,
    Ciot_cloud_topic_access,
    Ciot_cloud_topic_binding,

    Ciot_cloud_topic_status,
    Ciot_cloud_topic_notify,

    Ciot_cloud_topic_action,
    Ciot_cloud_topic_queue,

    Ciot_cloud_topic_request,
    Ciot_cloud_topic_response,
#if ENABLE_OTA
    Ciot_cloud_topic_ota,
#endif
    Ciot_cloud_topic_MAX

} Ciot_cloud_topic;

typedef enum Ciot_cloud_connection_status_e {
    Ciot_cloud_connection_status_idle = 0,
    Ciot_cloud_connection_status_ready,
    Ciot_cloud_connection_status_start_failed,
    Ciot_cloud_connection_status_connecting,
    Ciot_cloud_connection_status_connected,
    Ciot_cloud_connection_status_timeout,
    Ciot_cloud_connection_status_auth_failed,
    Ciot_cloud_connection_status_no_access,
    Ciot_cloud_connection_status_binding_failed,
    Ciot_cloud_connection_status_binding_ok,
    Ciot_cloud_connection_status_connecting_channel,
    Ciot_cloud_connection_status_succeed,

    Ciot_cloud_connection_status_MAX
} Ciot_cloud_connection_status;

typedef struct ciot_product_data_t {
    uint8_t id;
    union {
        bool bool_v;
        int64_t int_v;
        double double_v;
        uint8_t enum_v;
        uint64_t bits_v;
        char *string_v;
        uint8_t *raw_v;
    };
    Ciot_product_data_type type;

    /**
     * Must specific when use  string, raw types
     */
    uint16_t len;

} ciot_product_data;

typedef     Ciot_res    (* CommandReceivedHandler)         ( const char * event, ciot_product_data ** args, uint16_t dp_count, const char * mid);
typedef     void        (* CloudStatusChangedHandler)      ( Ciot_cloud_connection_status status );
typedef     Ciot_res    (* CommandRawReceivedHandler)      ( int eventId, const char * event, const cJSON * args, const char * mid );
typedef     Ciot_res    (* DpCommandReceivedHandler)       ( const ciot_product_data ** data, uint16_t dp_count, const char * mid );
#if ENABLE_OTA
typedef     Ciot_res    (* WatchCheckVersionHandler)      ( int eventId, const char * event, const cJSON * args );
#endif
typedef     Ciot_res    (* APIReceivedHandler)             ( const char * api, const cJSON * content, Ciot_res status, const char * message );

typedef struct ciot_cloud_manager_t
{
    /**
     * Struct method
     */
    Ciot_res    (* report_status)             ( ciot_product_data status, const char * mid );
    Ciot_res    (* report_status_force)       ( ciot_product_data status, const char * mid );


    /**
     * pointer method
     */
    Ciot_res    (* report_status_data)        ( ciot_product_data * status, const char * mid );
    Ciot_res    (* report_status_data_force)  ( ciot_product_data * status, const char * mid );


    /**
     * pointer method & bulk pointers 
     */
    Ciot_res    (* report_dp)                 ( const ciot_product_data * data, const char * mid );
    Ciot_res    (* report_dps)                ( const ciot_product_data ** data, uint16_t dp_count, const char * mid );

    /**
     * notify without message
     */
    Ciot_res    (* report_notify)             ( uint16_t eventID, const char * event, const char * mid );

    /**
     * notify with message (string, json-string)
     */
    Ciot_res    (* report_notify_message)     ( uint16_t eventID, const char * event, const char * string_message, const char * mid);


    /**
     * @deprecated
     */
    Ciot_res    (* command_received)          ( const char * event, ciot_product_data ** args, uint16_t dp_count, const char * mid );

    Ciot_res    (* command_raw_received)       ( int eventId, const char * event, const cJSON * args, const char * mid );

#if ENABLE_OTA
    Ciot_res    (* watch_check_version)       ( int eventId, const char * event, const cJSON * args );
#endif
    Ciot_res    (* dp_command_received)       ( const ciot_product_data ** data, uint16_t dp_count, const char * mid );

    Ciot_res    (* system_command_received)   ( int eventId, const char * event, const cJSON * args, const char * mid );

    void        (* cloud_status_changed)      ( Ciot_cloud_connection_status status );

    /**
     * APIs
     *
     */

    /**
     * Request API by Ciot cloud
     * param api, payload need to be release when done
     * @param api (used in event name)
     * @param payload
     * @return
     */
    Ciot_res    (* api_request)               ( const char * api, const cJSON * payload );

    /**
     * API Response by Ciot cloud
     * @param api
     * @param content
     * @param status
     * @param message
     * @return
     */
    Ciot_res    (* api_response)              ( const char * api, const cJSON * content, Ciot_res status, const char * message );

} ciot_cloud_manager;

CIOT_PRIVATE
const ciot_cloud_manager * ciot_cloud_manager_init();

CIOT_API
const ciot_cloud_manager * ciot_cloud_manager_instance();

CIOT_API
Ciot_res ciot_cloud_set_command_received_handler( CommandReceivedHandler handler );

CIOT_API
// Ciot_res ciot_cloud_set_command_raw_received_handler( CommandRawReceivedHandler handler );
Ciot_res ciot_cloud_set_dp_command_received_handler( DpCommandReceivedHandler handler );

#if ENABLE_OTA
CIOT_API
Ciot_res ciot_cloud_watch_checkVersion( WatchCheckVersionHandler handler );
#endif

CIOT_API
Ciot_res ciot_cloud_set_cloud_status_changed_handler( CloudStatusChangedHandler handler );

CIOT_API
Ciot_res ciot_cloud_set_api_response_handler( APIReceivedHandler handler );

#define ciot_cloud_mgr()    ciot_cloud_manager_instance()
#define ciot_cloud()        ciot_cloud_mgr()

const char * ciot_cloud_get_validate_sign( Ciot_time_ms timestamp, const char * nonce );
// need to free the return value

bool ciot_cloud_check_validate_sign( const char * pid, const char * did, Ciot_time_ms timestamp, const char * nonce, const char * sign );

/**
 * Data Point transmit Type
 * 数据点传输类型
 * '1' both '2' control '3' report
 * '1' 双向 '2' 控制 '3' 上报
 */
typedef enum Ciot_product_dp_transmit_type_e {
    Ciot_product_dp_transmit_type_none = 0,
    Ciot_product_dp_transmit_type_report = 1,
    Ciot_product_dp_transmit_type_control = 2,
    Ciot_product_dp_transmit_type_both = 3,

    Ciot_product_dp_transmit_type_MAX
} Ciot_product_dp_transmit_type;

/**
 * Bool DP Extra Definition
 * 布尔型数据点定义
 */
typedef struct Ciot_product_bool_point_def_t{
    int dp_id;
    int bool_count;
    const char ** names;
} Ciot_product_bool_point_def;

/**
 * Enum DP Extra Definition
 * 枚举型数据点定义
 */
typedef struct Ciot_product_enum_point_def_t{
    int dp_id;
    int enum_count;
    const char ** names;
} Ciot_product_enum_point_def;

/**
 * Int DP Extra Definition
 * 整型数据点定义
 */
typedef struct Ciot_product_int_point_def_t{
    int dp_id;
    int min;
    int max;
    int step;
    const char * unit;
} Ciot_product_int_point_def;

/**
 * Bits DP Extra Definition
 * 位图型数据点定义
 */
typedef struct Ciot_product_bits_point_def_t{
    int dp_id;
    int bits_count;
    const char ** names;
} Ciot_product_bits_point_def;

/**
 * Product Data Point Definition
 * 产品数据点定义
 */
typedef struct Ciot_product_point_def_t{

    const char * machineID; // String -> String

    /**
     * 数据类型
     */
    Ciot_product_data_type type; // String -> int
    /**
     * 指令代码
     */
    const char * code;      // String -> String

    /**
     * 云端ID
     */
    const char * id;        // String -> String

    /**
     * 名称，备注
     */
    const char * name;      // String -> String
    const char * remark;    // String -> String

    /** DP ID */
    int dp_id;

    /**
     * 是否可重复上报
     */
    bool repeat;            //  0/1 -> bool
    /**
     * 传输类型
     */
    Ciot_product_dp_transmit_type transmit_type; // ('1' both '2' control '3' report) -> Ciot_product_dp_transmit_type

    Ciot_product_bool_point_def * bool_def;
    Ciot_product_enum_point_def * enum_def;
    Ciot_product_int_point_def * int_def;
    Ciot_product_bits_point_def * bits_def;

} Ciot_product_point_def;

/**
 * Machine Data Point Definitions
 * 设备数据点定义集合
 */
typedef struct Ciot_machine_dp_defs_t {
    char * machineID;
    int dp_count;
    Ciot_product_point_def ** defs;
} Ciot_machine_dp_defs;


static int _st_ciot_dp_machine_count = 0;
static Ciot_machine_dp_defs ** _st_ciot_machine_defs = NULL;

static Ciot_machine_dp_defs * ciot_cloud_init_dp_defs_from_json( const cJSON * json );
static Ciot_res ciot_cloud_deinit_dp_defs(Ciot_machine_dp_defs * defs);

Ciot_res ciot_cloud_init_machine_group( const cJSON * data);
Ciot_res ciot_cloud_deinit_machine_group();

int ciot_cloud_get_dp_machine_count();

static const Ciot_product_point_def **  ciot_cloud_get_dp_defs();
const Ciot_product_point_def * ciot_cloud_get_dp_def_by_code( const char * code, const char * machineID );
const Ciot_product_point_def * ciot_cloud_get_dp_def_by_id( int dpid, const char * machineID );

#ifdef __cplusplus
}
#endif

#endif //CIOT_CSDK_CIOT_CLOUD_H
